Software-based systems are considered to be some of the most complex artifacts developed and managed by mankind. The single largest factor contributing to software-based system complexity is the combinatorial impact of variances of conditional logic. For a software-based system having a set of N condition variables defining its state, a deterministic logic has to unequivocally define the system's correct behavior in all N−1 permutations and combinations of those variables. As software-based systems have grown in their scope and application, such complexity has increasingly degraded their over-all quality, performance, predictability and manageability.
The evolution of software development into software engineering illustrates how this high degree of complexity has been approached. The discipline of software engineering itself was intended to transform software development from what was previously mostly an art form into more of a science. Accordingly, software engineering attempted to define a general theory of software development, from which related methods and processes could be deduced, and applied to real problems. During what may be considered the first generation of software engineering, software developers employed functional decomposition techniques. Using functional decomposition, software systems are constructed using a top-down approach, through successive refinement of software modules encapsulating increasingly more granular function points. In these techniques, implied or explicit deliverables of a “Structured Analysis” requirements analysis method are translated into a “Structured Design” top-down design, from which implied or explicit deliverables are translated into “Structured Programming” constructs.
Notwithstanding the benefits obtained by consistent application of functional decomposition, every change in the state variables of the resulting software-based systems, or in the conditions that bind them to each either, still triggered a ‘ripple effect’ requiring identification of all impacted function points, and potentially refinement of conditional logic in many code modules. Thus, while educating and training software developers was made easier, the manageability of increasing complex software-based systems was not substantially improved.
Object-based software development emerged in the 1980s, and changed the defining principle behind software modules from structured functions to abstract data types. Abstract data types leverage the fact that data objects are more stable anchors for software system design than the ever changing function points. In object-based software development, the principle of information hiding allows modules to isolate changes in their variances from other modules by providing access methods for their associated data. The conceptual premise of object-based software development, and the preliminary indications of increased productivity and reliability, were well received. For example, the United States Department of Defense issued requirements for using the ADA object-based programming language in its software-based systems.
Unfortunately, the benefits of object-based software development proved to be exaggerated. A key limitation was the requirement to pre-design and pre-program all permutations and combinations of abstract data types as distinctively typed software modules. Once again, the inherent complexity of the combinatorial impact of significant code changes after compilation, and potentially after deployment, became a limiting factor.
The introduction of object-oriented (OO) software development added late-binding through run-time instantiation of objects, and the principle of inheritance became a primary method for providing objects with late-binding in object-oriented systems. Object-oriented programming languages, such as C++, Eiffel, Java, and C#, provide inheritance for abstract data-types of objects that are typed when they are instantiated at run-time. In this type of system, a class is a software module encapsulating an abstract data-type, similar to the package concept in an object-based language, while an object is an instance of a class that is generated at run-time. A class can be defined as an extension (an “heir”) of another class, and thereby “inherit” the methods and properties of that other class, and reuse them in the heir class. Inheritance often eliminates the need to recode common methods and properties for different classes. In addition to using inherited methods and properties, an inheriting class can also override them as well as add new methods and properties of its own. Advantageously, a change to a given class is automatically applied to all its heirs.
Run-time systems supporting object orientation enable late-binding of objects through inheritance graphs that are pre-defined by the objects' classes. A linker, compiler or interpreter generates the instruction-set for traversing the inheritance graph of a set of software components compiled together as a single binary module. The run-time system instantiates the objects and resolves their methods and properties in accordance with the inheritance graphs of their binding modules. Single Inheritance, Multiple Inheritance and Interface Inheritance are featured in various ones of these systems. Polymorphism is a complementary technique available through object-oriented systems for enabling multiple implementations of methods. However, polymorphism is highly discouraged by software engineering methodologies due to its infringement of the principle of information hiding.
Object-oriented software development technologies have become the preferred tools for software engineering. Most software allows the use of object-oriented systems, thus enabling late-binding through Inheritance, either through a programming language's specific run-time system (i.e. Java), or through a run-time system shared by multiple programming languages (i.e. Microsoft.Net). Unfortunately, the success of object-oriented software in reducing overall complexity has been limited.
First, it should be recognized that the inheritance relationships for object-oriented programs developed using existing object-oriented systems are pre-defined at compile time or (link time) by their classes. All components in a given inheritance graph have to be compiled together into a single binary module, and a change to any component may require re-compiling, possibly re-linking, and re-deploying of a new binary module. Accordingly, singular or relatively limited changes can impact software system deployment. Second, since inheritance is tightly-coupled to a given set of classes, a change in any given class may impact all the heirs of that class. Accordingly, a large number of potential side-effects on other classes may need to be carefully evaluated and tested.
These shortcomings relate significantly to the fact that inheritance is a class property rather than an object property, as well as to the limitation of bounding the late-binding of application objects to the single inheritance graph of their classes as defined for each application at compile time. As shown in FIG. 1, an inheritance relationship 10 between Class1 and Class2 is present at Design-Time 12, when the Object Definitions 16a are provided, while at Run Time 18 the Compiled Code 14 following compilation 15 instantiates Runtime Objects 16 resulting in Object Instances O1a and O2a. As shown in FIG. 2, a desired change 20 may need to be made through a design time change 22, and result in re-compiling 24, followed by re-deployment of the new version of the Compiled Code 26, and possibly updating the Runtime Objects 16 through the new Object Definitions 17a resulting in Object Instances O1b and O2b in the new Runtime Objects 17b. 
FIGS. 3 and 4 illustrate the effect of the fact that Inheritance in existing systems is tightly-coupled to a development time class hierarchy. In FIG. 3, a change to Class C19 31 in the Class hierarchy 32 is made at development time 30 in order to change the associated class program 36 in the class programs 38 after compilation 34. As a result, at Run-Time 39, within the data objects 42 used at Run-Time 39, there are associated changed data objects 40. In FIG. 4, at development time 64, a change to the Class C2 50 results in changes to its heir Classes 52. After compilation 58, the class programs 56 include modified class programs 54, which result in the modified data objects 60 at Run-Time 66.
Thus, as shown in FIGS. 3 and 4, the principle of inheritance can explode the total number of changes needed to provide a significant program change at a high level within the class hierarchy of a program. Accordingly, the complexity represented in the class hierarchy is still a fundamental problem when maintaining and modifying a software-based system. The use of inheritance in programming therefore becomes an exercise in trade-offs, since the reduced complexity enabled by late binding comes with a degree of increased complexity in managing side-effects of code modifications in a given application. Furthermore, notwithstanding any of the current advancement in modern compilers, integrated development environments and runtime system frameworks, the utility of object-oriented software engineering methods to contemporary applications is still bounded by two fundamental system-level limitations:
1) the scope of late-binding is limited to the inheritance-graph of a given application; and
2) the utility of late-binding is limited to a single phase in objects' life-cycle: while they are stored in-memory. At all other phases in the life-cycle, before and after objects are loaded into the computer's memory, are managed by different systems using different methods.
While database systems indeed manage the persistent storage of data derived from objects, neither late-binding nor other aspects of these objects, as indicated by their applications, are being applied to persistent storage. As a result, it can be said that years of practicing object-oriented methods with current systems has resulted in only a minimal net contribution to the reduction of costs and complexity, particularly as encountered when modifying previously deployed software-based systems.